/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.vos.admin.CacheVo;
import cn.easyplatform.messages.vos.admin.CachesVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.service.ServiceLocator;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.*;

import java.sql.RowId;
import java.util.*;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class CacheController extends SelectorComposer<Component> implements EventListener<Event> {

    @Wire("grid#entityList")
    private Grid entityList;

    @Wire("grid#resourceList")
    private Grid resourceList;

    @Wire("checkbox#entityEnabled")
    private Checkbox entityEnabled;

    @Wire("checkbox#resourceEnabled")
    private Checkbox resourceEnabled;

    @Wire("button#refreshEntity")
    private Button refreshEntity;

    @Wire("button#resetEntity")
    private Button resetEntity;

    @Wire("button#refreshResource")
    private Button refreshResource;

    @Wire("button#resetResource")
    private Button resetResource;

    @Wire("bandbox#findResource")
    private Bandbox findResource;

    @Wire("bandbox#findEntity")
    private Bandbox findEntity;

    private List<CacheVo> entityData;

    private List<CacheVo> resourceData;

    private Map<String, Group> group = new HashMap<String, Group>();

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.initCache(new SimpleRequestMessage());
        if (resp.isSuccess()) {
            CachesVo cvs = (CachesVo) resp.getBody();
            entityEnabled.setChecked(cvs.isEntityEnabled());
            resourceEnabled.setChecked(cvs.isResourceEnabled());
            setDisabled("Entity", cvs.isEntityEnabled());
            setDisabled("Resource", cvs.isResourceEnabled());
            this.entityData = cvs.getEntityList();
            this.resourceData = cvs.getResourceList();
            if (!this.entityData.isEmpty())
                entityData.sort(Comparator.comparing(CacheVo::getType));
            drawEntityList(entityData);
            drawResourceList(this.resourceData);
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }

    @Listen("onCheck = checkbox#resourceEnabled; onCheck=checkbox#entityEnabled")
    public void onEnabled(Event event) {
        String type = event.getTarget().getId().startsWith("entity") ? "Entity" : "Resource";
        Checkbox cbx = ((Checkbox) event.getTarget());
        Messagebox.show(Labels.getLabel("admin.service.op.confirm", new String[]{cbx.isChecked() ? Labels.getLabel("button.open") : Labels.getLabel("msn.close")}), Labels.getLabel("admin.service.op.title"), Messagebox.NO | Messagebox.OK,
                Messagebox.QUESTION, new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        if (event.getName().equals(Events.ON_OK)) {
                            Object[] data = new Object[2];
                            data[0] = type;
                            data[1] = cbx.isChecked();
                            AdminService as = ServiceLocator.lookup(AdminService.class);
                            IResponseMessage<?> resp = as.enableCache(new SimpleRequestMessage(data));
                            if (resp.isSuccess()) {
                                if (!cbx.isChecked()) {
                                    if ("Entity".equals(type))
                                        entityList.getRows().getChildren().clear();
                                    else
                                        resourceList.getRows().getChildren().clear();
                                }
                                if ("Entity".equals(type))
                                    setDisabled("Entity", cbx.isChecked());
                                else
                                    setDisabled("Resource", cbx.isChecked());
                            } else {
                                MessageBox.showMessage(resp);
                                cbx.setChecked(!cbx.isChecked());
                                if ("Entity".equals(type))
                                    setDisabled("Entity", cbx.isChecked());
                                else
                                    setDisabled("Resource", cbx.isChecked());
                            }
                        } else {
                            cbx.setChecked(!cbx.isChecked());
                            if ("Entity".equals(type))
                                setDisabled("Entity", !cbx.isChecked());
                            else
                                setDisabled("Resource", !cbx.isChecked());
                        }
                    }
                });
    }

    private void setDisabled(String type, boolean enabled) {
        if ("Entity".equals(type)) {
            refreshEntity.setDisabled(!enabled);
            resetEntity.setDisabled(!enabled);
            findEntity.setDisabled(!enabled);
        } else {
            refreshResource.setDisabled(!enabled);
            resetResource.setDisabled(!enabled);
            findResource.setDisabled(!enabled);
        }
    }

    @Listen("onClick=button#refreshEntity;onClick=button#refreshResource")
    public void onRefresh(Event event) {
        String type = event.getTarget().getId().substring(7);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getCacheList(new SimpleRequestMessage(type));
        if (resp.isSuccess()) {
            if (type.equals("Entity")) {
                this.entityData = (List<CacheVo>) resp.getBody();
                if (!this.entityData.isEmpty())
                    entityData.sort(Comparator.comparing(CacheVo::getType));
                this.drawEntityList(entityData);
            } else {
                this.resourceData = (List<CacheVo>) resp.getBody();
                this.drawResourceList(this.resourceData);
            }
        } else {
            MessageBox.showMessage(resp);
        }
    }

    @Listen("onClick=button#resetResource;onClick=button#resetEntity")
    public void onReset(Event event) {
        String type = event.getTarget().getId().substring(5);
        Messagebox.show(Labels.getLabel("admin.service.op.confirm", new String[]{Labels.getLabel("admin.cache.reset")}), Labels.getLabel("admin.service.op.title"), Messagebox.NO | Messagebox.OK,
                Messagebox.QUESTION, new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        if (event.getName().equals(Events.ON_OK)) {
                            AdminService as = ServiceLocator.lookup(AdminService.class);
                            IResponseMessage<?> resp = as.resetCache(new SimpleRequestMessage(type));
                            if (resp.isSuccess()) {
                                if (type.equals("Entity"))
                                    entityList.getRows().getChildren().clear();
                                else
                                    resourceList.getRows().getChildren().clear();
                            } else {
                                MessageBox.showMessage(resp);
                            }
                        }
                    }
                });
    }

    private void drawResourceList(List<CacheVo> data) {
        resourceList.getRows().getChildren().clear();
        for (CacheVo cv : data) {
            Row row = new Row();
            row.appendChild(new Label(cv.getId()));
            row.appendChild(new Label(cv.getName()));
            Div div = new Div();
            Button refresh = new Button();
            refresh.setIconSclass("z-icon-repeat");
            refresh.setTooltiptext(Labels.getLabel("admin.project.load.db"));
            refresh.setParent(div);
            refresh.addEventListener(Events.ON_CLICK, this);
            Button delete = new Button();
            delete.setIconSclass("z-icon-times");
            delete.setSclass("ml-2");
            delete.setTooltiptext(Labels.getLabel("admin.event.clear"));
            delete.setParent(div);
            delete.addEventListener(Events.ON_CLICK, this);
            row.setValue(cv);
            row.appendChild(div);
            resourceList.getRows().appendChild(row);
        }
    }

    private void drawEntityList(List<CacheVo> data) {
        entityList.getRows().getChildren().clear();
        group.clear();
        for (CacheVo cv : data) {
            Group g = group.get(cv.getType());
            if (g == null) {
                g = new Group(cv.getType());
                g.setParent(entityList.getRows());
                group.put(cv.getType(), g);
            }
            Row row = new Row();
            row.appendChild(new Label(cv.getId()));
            row.appendChild(new Label(cv.getName()));
            row.appendChild(new Label(cv.getDescription()));
            Div div = new Div();
            Button refresh = new Button();
            refresh.setIconSclass("z-icon-repeat");
            refresh.setTooltiptext(Labels.getLabel("admin.project.load.db"));
            refresh.setParent(div);
            refresh.addEventListener(Events.ON_CLICK, this);
            Button delete = new Button();
            delete.setIconSclass("z-icon-times");
            delete.setSclass("ml-2");
            delete.setTooltiptext(Labels.getLabel("admin.event.clear"));
            delete.setParent(div);
            delete.addEventListener(Events.ON_CLICK, this);
            row.setValue(cv);
            row.appendChild(div);
            entityList.getRows().getChildren().add(entityList.getRows().getChildren().indexOf(g) + 1, row);
        }
    }

    @Listen("onOpen=bandbox#findEntity;onOpen=bandbox#findResource")
    public void onFindEntity(OpenEvent oe) {
        String key = (String) oe.getValue();
        String type = oe.getTarget().getId().substring(4);
        if (!Strings.isBlank(key)) {
            if (type.equals("Entity")) {
                if (entityData == null || entityData.isEmpty())
                    return;
                List<CacheVo> searchs = new ArrayList<>();
                for (CacheVo vo : entityData) {
                    if (vo.getId().indexOf(key) >= 0 || vo.getName().indexOf(key) >= 0)
                        searchs.add(vo);
                }
                drawEntityList(searchs);
            } else {
                if (resourceData == null || resourceData.isEmpty())
                    return;
                List<CacheVo> searchs = new ArrayList<>();
                for (CacheVo vo : resourceData) {
                    if (vo.getId().indexOf(key) >= 0 || vo.getName().indexOf(key) >= 0)
                        searchs.add(vo);
                }
                drawResourceList(searchs);
            }
        } else {
            if (type.equals("Entity"))
                drawEntityList(this.entityData);
            else
                drawResourceList(this.resourceData);
        }
    }

    private void reload(final String type) {
        Messagebox.show(Labels.getLabel("admin.service.op.confirm", new String[]{Labels.getLabel("admin.cache.reload")}), Labels.getLabel("admin.service.op.title"), Messagebox.NO | Messagebox.OK,
                Messagebox.QUESTION, new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        if (event.getName().equals(Events.ON_OK)) {
                            AdminService as = ServiceLocator.lookup(AdminService.class);
                            IResponseMessage<?> resp = as.reloadCache(new SimpleRequestMessage(type));
                            if (resp.isSuccess()) {

                            } else
                                MessageBox.showMessage(resp);
                        }
                    }
                });
    }

    @Override
    //@Listen("onClick=grid#applist > rows > row > hlayout > a")
    public void onEvent(Event event) throws Exception {
        Row row = (Row) event.getTarget().getParent().getParent();
        if (event.getTarget().getParent().getChildren().indexOf(event.getTarget()) == 0) {//第1个组件
            refresh(row, row.getGrid() == resourceList ? "Resource" : "Entity");
        } else {
            remove(row, row.getGrid() == resourceList ? "Resource" : "Entity");
        }
    }

    private void refresh(Row row, String type) {
        CacheVo cv = row.getValue();
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.reloadCache(new SimpleRequestMessage(new String[]{type, cv.getId()}));
        if (resp.isSuccess()) {
            CacheVo vo = (CacheVo) resp.getBody();
            row.setValue(vo);
            ((Label) row.getChildren().get(1)).setValue(vo.getName());
            ((Label) row.getChildren().get(2)).setValue(vo.getDescription());
        } else
            MessageBox.showMessage(resp);
    }

    private void remove(final Row row, final String type) {
        Messagebox.show(Labels.getLabel("admin.service.op.confirm", new String[]{Labels.getLabel("admin.event.clear")}), Labels.getLabel("admin.service.op.title"), Messagebox.NO | Messagebox.OK,
                Messagebox.QUESTION, new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event) throws Exception {
                        if (event.getName().equals(Events.ON_OK)) {
                            CacheVo cv = row.getValue();
                            AdminService as = ServiceLocator.lookup(AdminService.class);
                            IResponseMessage<?> resp = as.deleteCache(new SimpleRequestMessage(new String[]{type, cv.getId()}));
                            if (resp.isSuccess()) {
                                row.detach();
                            } else
                                MessageBox.showMessage(resp);
                        }
                    }
                });
    }
}
